import { observable, action, toJS } from 'mobx';
import { WeaTools } from "ecCom";
import EditorUtil from "../../util/ckextraEditorUtil";

const ID_PRE = 'revision_';
export default class RevisionItem {
  @observable author = '';
  @observable text = '';
  node = null;//实际对应的节点，不一定有值。
  @observable type = '';//D 删除， I 新增
  @observable datetime;
  @observable containedPostilIds = ''; // 对应批注的id

  id = -1;
  parent = null;
  revisionCk = null;

  constructor(params) {
    if (params) {
      this.parent = params.parent;
      this.revisionCk = params.revisionCk;
      if (params.node) {
        this.text = EditorUtil.clearEmptyChar(params.node.getText());
        this.author = params.node.getAttribute("xiudingren");
        this.datetime = params.node.getAttribute("xiudingshijian");
        this.containedPostilIds = params.node.getAttribute('containedPostilIds') || '';
        if (this.datetime) {
          this.datetime = this.datetime.replace('T', ' ').replace('Z', '');
        }
        this.node = params.node;
        let id = params.node.getId() || params.id;
        if (typeof(id) === 'string') {
          id = parseInt(id.replace(ID_PRE, ''));
        }
        this.id = id;
      } else {
        if (params.text) {
          this.text = params.text;
        }
        if (params.author) {
          this.author = params.author;
        }
        if (params.datetime) {
          if (typeof(params.datetime) === 'string') {
            this.datetime = params.datetime;
          } else if (typeof(params.datetime) === 'number') {
            this.datetime = WeaTools.formatRealDate(new Date(params.datetime), 'yyyy-MM-dd HH:mm:ss');
          } else if (params.datetime instanceof Date) {
            this.datetime = WeaTools.formatRealDate(params.datetime, 'yyyy-MM-dd HH:mm:ss');
          }
        }
        if (params.id) {
          this.id = params.id;
        }
        if (params.containedPostilIds) { // 记录删除批注包含的修订的id
          this.containedPostilIds = params.containedPostilIds;
        }
      }
      this.type = params.type === 'D' ? 'D' : params.type === 'T'? 'T' : 'I';
    }
    this.author || (this.author = CKEditorParams.author);
    this.datetime || (this.datetime = WeaTools.formatRealDate(new Date(), 'yyyy-MM-dd HH:mm:ss'));
  }


  @action
  setState = (state) => {
    for (let key in state) {
      this[key] = state[key];
    }
  }

  createDom = (revision) => {
    if (this.type === 'D') {
      let createdElement = EditorUtil.getEditor().document.createElement('s', {
        attributes: {
          class: 'odoc_delTag',
          xiudingren: this.author,
          xiudingshijian: this.datetime.replace(' ', 'T') + 'Z',
          id: (this.id !== -1) ? (ID_PRE + this.id) : '',
          containedPostilIds: this.containedPostilIds,
        },
      });
      createdElement.setText(this.text || '');
      return createdElement;
    } else if (this.type === 'T') {
      let createdElement = EditorUtil.getEditor().document.createElement('tempText');
      createdElement.setText(this.text || '\u200B\u200B\u200B\u200B\u200B\u200B\u200B');
      return createdElement;
    } else {
      let createdElement = EditorUtil.getEditor().document.createElement( 'u', {
        attributes: {
          class: 'odoc_insertTag',
          xiudingren: this.author,
          xiudingshijian: this.datetime.replace(' ', 'T') + 'Z',
          id: this.id !== -1 ? (ID_PRE + this.id) : '',
          containedPostilIds: this.containedPostilIds,
        },
      });
      createdElement.setText(this.text || '');
      return createdElement;
    }
  }

  createDomList = (revision, list) => {// list加入是为了处理修订更改的时候，原本的批注保留
    let domList = [];
    if (this.type === 'D') {
      let createdElement = EditorUtil.getEditor().document.createElement('s', {
        attributes: {
          class: 'odoc_delTag',
          xiudingren: this.author,
          xiudingshijian: this.datetime.replace(' ', 'T') + 'Z',
          id: (this.id !== -1) ? (ID_PRE + this.id) : '',
          containedPostilIds: this.containedPostilIds,
        },
      });
      domList = this.transcreatedElement(createdElement, list);
    } else if (this.type === 'T') {
      let createdElement = EditorUtil.getEditor().document.createElement('tempText');
      createdElement.setText(this.text || '\u200B\u200B\u200B\u200B\u200B\u200B\u200B');
      domList = [{
        dom: createdElement,
        type: '',
      }];
    } else {
      let createdElement = EditorUtil.getEditor().document.createElement( 'u', {
        attributes: {
          class: 'odoc_insertTag',
          xiudingren: this.author,
          xiudingshijian: this.datetime.replace(' ', 'T') + 'Z',
          id: this.id !== -1 ? (ID_PRE + this.id) : '',
          containedPostilIds: this.containedPostilIds,
        },
      });
      domList = this.transcreatedElement(createdElement, list);
    }
    return domList;
  }

  // 有批注的情况下，需要保留。最开头和最末尾的情况，需要拿出来，其他逐个插入createdElement中
  transcreatedElement = (createdElement, list) => {
    const newList = [];
    let startP = null;
    let endP = null;
    if (list && list.length > 1) {
      list.forEach(({item}, index) => {
        if (item.type === 'P') {
          const postilNode = EditorUtil.getEditor().document.createElement("postil", {attributes: {...item.attributes}});
          if (index === 0) {
            startP = postilNode;
          } else if (index === list.length - 1) {
            endP = postilNode;
          } else {
            createdElement.append(postilNode);
          }
          createdElement.append(postilNode);
        } else {// 修订插入文本
          const textNode = document.createTextNode(item.text);
          createdElement.appendText(item.text);
        }
      });
    } else {
      createdElement.setText(this.text || '');
    }
    if (startP) {
      newList.push({
        dom: startP,
        type: 'postil',
      });
    }
    newList.push({
      dom: createdElement,
      type: ''
    });
    if (endP) {
      newList.push({
        dom: endP,
        type: 'postil',
      });
    }
    return newList;
  }

  receive = () => {
    if (!this.node && this.id !== -1) this.node = RevisionItem.findNodeById(this.id);
    if (!this.node) return;
    if (this.type === 'D') this.node.remove();
    else this.node.$.outerHTML = this.node.$.innerHTML;
  }

  reject = () => {
    if (!this.node && this.id !== -1) this.node = RevisionItem.findNodeById(this.id);
    if (!this.node) return;
    if (this.type === 'D') this.node.$.outerHTML = this.node.$.innerHTML;
    else this.node.remove();
  }


  static getNodeRevisionType = (node, transP) => { // transP： 是否转化Postil
    if (EditorUtil.isElement(node)) {
      if (node.getName() === 's') return 'D';
      else if (node.getName() === 'u') return 'I';
      else if (node.getName() === 'temptext') return 'T';
      // 增加对postil标签的处理
      else if (transP && node.getName() === 'postil') return 'P';
    }
    return '';
  }

  // 检测节点是否在revision下，在的话返回相应的type，否则返回''
  static checkRevisionType = (node) => {
    if (!EditorUtil.isNode(node) || EditorUtil.isParagraph(node)) return '';
    return RevisionItem.getNodeRevisionType(node) || RevisionItem.checkRevisionType(node.getParent());
  }

  static mergeNode = (node, revision) => {
    let list = RevisionItem.convertDomToList(node);// 从node节点中转换出所有的文本节点。（需要保留postil节点）
    // 将需要合并的节点放到一个mergeObject中，将所有mergeObject放到mergeList中。
    let mergeList = [], mergeObject = null;
    const needNewMerge = (item) => !mergeObject /*|| Math.abs(mergeObject.time - new Date(item.datetime).getTime()) > 5000 */|| item.author !== mergeObject.author || item.type !== mergeObject.type;
    list.forEach((itemNode) => {
      let postilList = [];
      let {item, node} = itemNode;
      if (!item) {
        mergeObject && mergeList.push(mergeObject);
        mergeObject = null;
        return;
      }
      if (item.type === 'P') {// postil标签单独处理: 存在mergeObject的时候，直接放入mergeObject的list，不存在的时候先记录下载，新建mergeObject的时候再放入
        if (!mergeObject) {
          postilList.push(itemNode);
        } else {
          mergeObject.list.push(itemNode);
        }
        return;
      }
      if (needNewMerge(item)) {
        mergeObject && mergeList.push(mergeObject);
        mergeObject = {
          time: new Date(item.datetime).getTime(),
          author: item.author,
          type: item.type,
          list: [],
          containedPostilIds: item.containedPostilIds || '',
        };
        // 如果是新的mergeObject，把存储的postilList放入
        if (postilList.length > 0) {
          postilList.forEach(ps => mergeObject.list.push(ps));
          postilList = [];
        }
      }
      if (item.children && item.children.length > 0) {
        if (!mergeObject.insertNode) mergeObject.insertNode = node;
        item.children.forEach((child) => {
          const isPostil = child.item.type === 'P';
          if (isPostil) {
            // 批注直接push到mergeObject.list
            mergeObject.list.push(child);
          } else {
            // 修订
            let childItem = child.item;
            if (needNewMerge(childItem)) {
              mergeObject && mergeList.push(mergeObject);
              mergeObject = {
                time: new Date(childItem.datetime).getTime(),
                author: childItem.author,
                type: childItem.type,
                containedPostilIds: childItem.containedPostilIds || '',
                list: [child],
                insertNode: node,
              };
            } else {
              if (mergeObject.time - new Date(child.datetime).getTime() < 0) {
                mergeObject.time = new Date(child.datetime).getTime();
              }
              mergeObject.list.push(child);
            }
          }
        } )
      } else {
        if (!mergeObject.insertNode) mergeObject.insertNode = node;
        if (mergeObject.time - new Date(item.datetime).getTime() < 0) {
          mergeObject.time = new Date(item.datetime).getTime();
        }
        mergeObject.list.push(itemNode);
      }
    } );
    mergeObject && mergeList.push(mergeObject);

    /**
     * 合并为revisionItem并过滤掉非修订节点;
     */
    let mergeItemList = mergeList.map((mergeObject,index) => {
      let {time, author, list, type, insertNode, containedPostilIds} = mergeObject;
      if (list.length === 0) return null;
      const isPostil = type === 'P'; //批注单独处理
      let text = EditorUtil.clearEmptyChar(list.map(({item}) => !isPostil && item.text).join(''));
      if (!text) return null;
      let mergeItem = {list, insertNode};
      mergeItem.item = new RevisionItem({datetime: time, text, author, type, containedPostilIds});
      return mergeItem;
    }).filter((mergeItem) =>  !!mergeItem);

    let usedIdMap = {};//使用过的id
    const getIdAndMarkFromList = (list) => {// 从列表中读取可用的id并记录无用的id。过滤掉了已在其它列表使用的id.
      let id;
      for (let i = 0;i<list.length;i++){
        let newId = list[i].item.id;
        if (newId === -1 || usedIdMap[newId]) continue;
        else {
          id = newId;
          usedIdMap[id] = true;
        }
      }
      return id;
    }
    // 遍历、生成id、生成节点、插入、移除旧节点
    mergeItemList.forEach(({item, list, insertNode}) => {
      if (item) {
        if (item.type === 'T') {
          const dom = new CKEDITOR.dom.text(item.text);
          dom.insertBefore(insertNode);
        } else {
          item.id = getIdAndMarkFromList(list) || -1;
          item.id = revision.mergeItem({...item});
          // dom = item.createDom(revision, list);
          // fix: 选择范围刚好是批注范围丢失postil标签的问题（最开始的时候直接拿出来）
          const domList = item.createDomList(revision, list);
          domList.forEach(domItem => {
            const {dom, type} = domItem;
            if (type == '' && !revision.revisionCk.revising) {
              if (item.type === 'I') {
                dom.addClass('hiddenRevision_u');
              } else if (item.type === 'D') {
                dom.addClass('hiddenRevision_s');
              }
            }
            dom.insertBefore(insertNode);
          });
        }
      }
    });
    mergeItemList.forEach(({insertNode, list}) => {
      list.forEach(({node}) => node.remove());
      insertNode.remove();
    } );
  } 

  static convertDomToList = (node, list) => {
    list = list || [];
    let item = RevisionItem.convertDomToItem(node);
    if (item) {
      let childCount = node.getChildCount();
      if (childCount > 0) {
        item.children = [];
        for (let i=0;i<childCount;i++) {
          let child = node.getChild(i);
          let childItem = RevisionItem.convertDomToItem(child);
          if (!childItem) {
            childItem = new RevisionItem({...item});
            childItem.text = child.getText();
          }
          // 避免左右移动u标签时修订列表乱动的问题
          if (childItem.text || child.$.nodeName === 'POSTIL') { // 批注的标签同样push
          // if (childItem.text) {
            item.children.push({item: childItem, node: child});
          }
        }
      }
      list.push({item, node});
      return list;
    }
    if (EditorUtil.isParagraph(node)) {
      list.push({});// 分割段落，避免将不同段落的合并到一起
    }
    if (EditorUtil.isElement(node)) {
      const children = node.getChildren().toArray();
      children.forEach((child) => RevisionItem.convertDomToList(child, list))
    } else {
      if (node.getText && node.getText() !== '') {
        list.push({node});
      }
    }
    return list;
  }

  static convertDomToItem = (node) => {
    let type = RevisionItem.getNodeRevisionType(node, true);
    if (!type) return null;
    if (type === 'P') {
      const PostilItem = {
        type,
        attributes: {...node.getAttributes()},
      }
      return PostilItem;
    }
    return new RevisionItem({node, type});
  }

  static findNodeById = (id) => {
    let editor = EditorUtil.getEditor(),
      insertNode = editor.document.getById(`${ID_PRE}${id}`),
      delNode = editor.document.getById(`${ID_PRE}${id}`);
    let node = insertNode || delNode || null;
    return node;
  }

  static findItemById = (id) => {
    let node = RevisionItem.findNodeById(id);
    return RevisionItem.convertDomToItem(node);
  }
}